package com.qianxing.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qianxing.dto.MessageReviewDTO;
import com.qianxing.exceptionhandler.ResponseException;
import com.qianxing.mapper.TbUserInfoMapper;
import com.qianxing.po.TbMsgReviewPO;
import com.qianxing.po.TbUserInfoPO;
import com.qianxing.service.TbMsgReviewService;
import com.qianxing.mapper.TbMsgReviewMapper;
import com.qianxing.service.TbUserInfoService;
import com.qianxing.utils.RedisContanct;
import com.qianxing.vo.TbMsgReviewVO;
import com.qianxing.vo.UserInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.qianxing.utils.RedisContanct.*;

/**
 * @author JasonLong
 * @description 针对表【tb_msg_review(推文评论数据表)】的数据库操作Service实现
 * @createDate 2023-09-15 00:28:02
 */
@Service
public class TbMsgReviewServiceImpl extends ServiceImpl<TbMsgReviewMapper, TbMsgReviewPO> implements TbMsgReviewService {

    private Logger LOGGER = LoggerFactory.getLogger(TbMsgReviewServiceImpl.class);

    private static final ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private TbUserInfoMapper userInfoMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TbMsgReviewMapper tbMsgReviewMapper;

    @Autowired
    private TbUserInfoService tbUserInfoService;

    /**
     * 存储评论
     *
     * @param reviewDTO
     * @return
     */
    @Override
    public ResponseException saveReview(MessageReviewDTO reviewDTO) {
        TbMsgReviewPO tbMsgReviewPO = new TbMsgReviewPO();
//        String token = stringRedisTemplate.opsForValue().get(LOGIN_USER_KEY);
        //用户未登录返回空
        if (StrUtil.isBlank(reviewDTO.getToken())) {
            return null;
        }
        //获取当前时间
        Date now = new Date();
        //TODO 时间格式化之类可以优化，提取当作一个工具类，以便于多模块通用
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = format.format(now);
        Date date = null;
        try {
            date = format.parse(formattedDateTime);
            System.out.println("格式化后的时间:" + date);
            //将时间存入数据库
            tbMsgReviewPO.setReviewDate(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        //通过userOpenId查询到对应的User数据
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.eq("user_openid", reviewDTO.getUserOpenId());
        TbUserInfoPO tbUserInfoPO = userInfoMapper.selectOne(wrapper);
        //评论用户
        tbMsgReviewPO.setUserNickname(tbUserInfoPO.getUserNickname());
        //评论用户头像
        tbMsgReviewPO.setUserAvatar(tbUserInfoPO.getUserAvatar());
        //评论用户的唯一ID
        tbMsgReviewPO.setUserOpenid(reviewDTO.getUserOpenId());
        //评论的对应文章的文章ID
        tbMsgReviewPO.setMsgId(reviewDTO.getReviewMsgId());
        //评论内容
        tbMsgReviewPO.setReviewMsg(reviewDTO.getReviewMsg());
        //生成当前评论ID
        String currentReviewId = RandomUtil.randomString(6);
        tbMsgReviewPO.setCurrentReviewId(currentReviewId);
        //TODO 多级评论逻辑判断
        LOGGER.info("===Get PO Data:===" + tbMsgReviewPO);
        boolean save = save(tbMsgReviewPO);
        //保持Redis与Mysql数据一致，更新数据库后先删除对应模块的缓存
        Boolean delete = stringRedisTemplate.delete(MSG_REVIEW_ID + reviewDTO.getToken());
        if (!save && !delete) {
            return ResponseException.error("500", "服务器错误！");
        }
        return ResponseException.success();
    }

    /**
     * 获取文章对应的评论
     *
     * @param msgId
     * @return
     */
    @Override
    public ResponseException getReviewByMsgId(String msgId, String token) throws JsonProcessingException {
        //TODO 先查询Redis
//        String tokenKey = stringRedisTemplate.opsForValue().get(LOGIN_USER_KEY+token);
        //用户未登录返回空
        if (StrUtil.isBlank(token)) {
            return null;
        }
        String reviewKey = RedisContanct.MSG_REVIEW_ID + token;
        //从Redis获取缓存数据
        String reviewDataInRedis = stringRedisTemplate.opsForValue().get(reviewKey);
        if (!StrUtil.isBlank(reviewDataInRedis)) {
            System.err.println("==REDIS REVIEW DATA==" + reviewDataInRedis);
            //Redis中存在数据，则直接返回数据
            List<TbMsgReviewVO> list = mapper.readValue(reviewDataInRedis, List.class);
//            List<TbMsgReviewVO> collect = list.stream().map(m -> {
//                TbMsgReviewVO tbMsgReviewVO = new TbMsgReviewVO();
//                tbMsgReviewVO.setUserOpenid(m.getUserOpenid());
//                tbMsgReviewVO.setReviewMsg(m.getReviewMsg());
//                tbMsgReviewVO.setReviewDate(m.getReviewDate());
//                tbMsgReviewVO.setUserAvatar(m.getUserAvatar());
//                tbMsgReviewVO.setUserNickname(m.getUserNickname());
//                return tbMsgReviewVO;
//            }).collect(Collectors.toList());
            return ResponseException.success(list);
        }
        //TODO Redis中不存在，再查询MySql,若mysql中也不存在，则需要加互斥锁，防止并发情况下对数据库造成空访问，即缓存穿透
        //判断是否命中缓存空对象
        if (reviewDataInRedis != null) {
            //命中则返回空null
            return null;
        }
        //TODO 未命中则进行数据库操作
        Boolean isLock = tryLock(msgId);
        try {
            //未成功获取锁
            if (!isLock) {
                Thread.sleep(50);
                //递归调用
                getReviewByMsgId(msgId, token);
            }
            //查询数据库
            QueryWrapper wrapper = new QueryWrapper<TbMsgReviewPO>();
            //查询指定msgId
            wrapper.eq("msg_id", msgId);
            //查询数据
            List<TbMsgReviewVO> list = tbMsgReviewMapper.selectList(wrapper);
            System.err.println("评论列表:==>>" + list.toString());
            if (list.size() == 0 || list.isEmpty()) {
                //缓存空对象
                stringRedisTemplate.opsForValue().set(reviewKey, "", 10L, TimeUnit.MINUTES);
                return null;
            }
            //建立缓存
            stringRedisTemplate.opsForValue().set(reviewKey, JSON.toJSONString(list), 20L, TimeUnit.MINUTES);
            return ResponseException.success(list);//由数据库返回

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            unLock(msgId);//释放锁
        }
    }

    //获取锁
    public Boolean tryLock(String msgIds) {
        Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(REVIEW_LOCK + msgIds, msgIds);
        return aBoolean;
    }

    //释放锁
    public Boolean unLock(String msgIds) {
        Boolean delete = stringRedisTemplate.delete(REVIEW_LOCK + msgIds);
        return delete;
    }
}




